iT邦幫忙

2022 iThome 鐵人賽

DAY 26
1
AI & Data

語言學與NLP系列 第 26

Day 26 循環神經網路 RNN 與 長短期記憶 LSTM 介紹與實作

  • 分享至 

  • xImage
  •  

今天開始就要進入神經網路的世界啦!首先介紹的就是循環神經網路(Recurrent Neural Network, RNN)。RNN 是什麼呢?為什麼要用 RNN?這一切的解答必須要先回到 Deep learning 最初的樣子----前饋神經網路(Feedforward Neural Network, FNN)。FNN 是最簡單的神經網路模型,資料是單向傳輸的。input 經由輸入層通過隱藏層(hedden layer)再到輸出層,其中的神經元(neuron)之間沒有連接迴路存在。如下圖所示:

FNN

圖片來源

然而,這樣單純的神經網路有以下幾特缺點:

  • 無法處理順序資料 (sequential data)

  • 僅考慮當前輸入

  • 無法記住以前的輸入

這些問題都能由 RNN 來解決,因為 RNN 可以處理順序資料,同時接受當前輸入和之前接收到的輸入,並且因為 RNN 有內部記憶體,所以 RNN 可以記住以前的輸入。

RNN 如何運作?

如圖所示:

RNN

圖片來源

RNN 的 input 會通過 loop 循環到中間 hidden layer。

  1. 輸入層 'x' 接收神經網路的輸入並對其進行處理,將其傳遞到中間層 'h'。

  2. 中間層 'h' 可以由多個循環的 hidden layers 組成,每個 hidden layer 都有自己的激勵函數 (Activation function)、權重和偏差。也就是說如果你希望你的神經網路是有記憶的,且每一層之間參數會互相影響,那就該選擇 RNN。

3.RNN 將不同的激勵函數、權重和偏差進行標準化(standardize),讓每個循環的 hidden layer 具有相同的參數。 也就是說整體而言 RNN 只會建立一個 hidden layer,再依據需要循環多次,才會有所謂多個循環的 hidden layers。(圖中向右側延伸的每一個 hidden layer 都是 'h' 這一個循環的 hidden layer 展開的樣子)

在 NLP 中 RNN 是非常常使用的神經網路,主要是因為分析語言必須考慮前後文之間的關聯,故採用有記憶的 RNN 是較佳的選擇。其中的應用包含機器翻譯、文本探勘與情緒分析等等。

RNN 的類型

RNN 又可分為 4 種類型:

  1. 一對一(one to one):這種類型的神經網路又稱為 Vanilla Neural Network,即最普通的 Neural Network 模型。 它用於具有單個輸入(input)和單個輸出(output)這種一般的機器學習問題。

onetoone

  1. 一對多(one to many):這種神經網路是單個輸入、多個輸出。Image caption就是一個例子。

onetomany

  1. 多對一(many to one):此 RNN 接受一系列輸入並生成單個輸出。像是情感分析(Sentiment Analysis)的分類問題就是這種例子,即一個句子(系列輸入),分類為表達積極或消極的情感(單一輸出:不是 positive 就是 negative)。

manytoone

  1. 多對多(many to many):該 RNN 接受一系列輸入並生成一系列輸出。例如機器翻譯(Machine Translation)。即一連串的句子輸入,產生一連串的句子(不同語言)的輸出。

manytomany

Standard RNN 的問題

  1. 梯度消失問題(Vanishing Gradient Problem):

梯度消失問題會出現在以梯度下降法和反向傳播訓練人工神經網路的時候。在每次訓練的迭代中,神經網路權重的更新值與誤差函數的偏導數成比例,然而在某些情況下,梯度值會幾乎消失。然而,梯度攜帶 RNN 中使用的資訊,當梯度變得太小時,參數更新變得不重要,會讓長序列資料的學習變得困難,甚至神經網路可能完全無法繼續訓練。

  1. 梯度爆炸問題(Exploding Gradient Problem):

梯度爆炸正好相反,當最初的權重值(w)過大時,w 乘以激勵函數的導數都大於 1 。這樣會讓神經網路前面層比後面層梯度變化更快,梯度爆炸就會因此產生。

而處理梯度問題的最流行和最有效的方法即長短期記憶網路(Long short-term memory, LSTM)。而了解 LSTM 之前必須先知道何謂長期依賴(Long-Term Dependencies)。

假設你想預測一篇文章中的一個單詞:「雲在____。」
最明顯的答案是 「天空」。我們不需要任何進一步的上下文來預測上述句子中的最後一個單詞。
但若換成這句話:「我在台北的公司待了 35 年,退休離開 _____ 之後,我想要出國去看看。」
在這裡,空格內填入任何一個地點都可以,而顯然最佳的答案「台北」是需要透過上下文,才能夠較好的預測。不過藉由這個句子會發現,若需要上下文的加入,相關資訊與所需資訊之間的差距可能會變得很大。而 LSTM 可以解决這樣的問題。

LSTM

LSTM 是一種特殊的 RNN,能够通過長時間記憶來學習長期依賴資訊。

所有 RNN 都是重複的神經網路模組,進而形成鏈的形式。 在 standard RNN 中,此重複模組的結構非常簡單,如圖所示:

single

LSTM 也有鏈狀結構,但重複模組的結構略有不同。它不是只有一個神經網路層,而是四個相互作用的層在進行訊息處理。如圖所示:

more

因此,我們將這樣略為複雜的結構放置到 standard RNN 之中就能改善前面所提到的問題了!

建構 LSTM 有 3 個主要要思考的步驟與方向:

  1. 忘記門:使用 sigmoid function 計算,確定在特定時間步長中應從記憶體中省略哪些資訊,即查看前一狀態(ht-1)和當前輸入xt,並計算函數。

forget

  1. 輸入門:這一層中有兩個部分,一個是 sigmoid 函數,另一個是 tanh 函數。在 sigmoid 函數中會决定要通過哪些值( 0 或 1 )。 tanh 函數為傳遞的值賦予權重,决定它們的重要程度( -1 到 1 )。

input

  1. 輸出門:第三步是决定輸出是什麼。 首先,sigmoid 層决定儲存格狀態的哪些部分被輸出。然後再將這個狀態轉換為 tanh,使其值介於 -1 和 1 之間,最後將這個值乘上前面 sigmoid gate 的輸出。

output

看完這麼多的介紹,我們來實作一下,預測股價吧!

RNN LSTM 實作

使用 Google_Stock_Price_Train:(https://www.kaggle.com/datasets/akram24/google-stock-price-train
)

和 Google_Stock_Price_Test:(https://www.kaggle.com/datasets/akram24/google-stock-price-test
) 資料集


import numpy as np
import matplotlib.pyplot as plt
import pandas as pd


dataset_train = pd.read_csv('/content/Google_Stock_Price_Train.csv')
training_set = dataset_train.iloc[:, 1:2].values


# 資料 scaling
from sklearn.preprocessing import MinMaxScaler

sc = MinMaxScaler(feature_range = (0,1))
training_set_scaled = sc.fit_transform(training_set)


# 從 scaled data 製作訓練集
X_train = []
y_train = []

for i in range(60, 1258):
  X_train.append(training_set_scaled[i-60:i, 0])
  y_train.append(training_set_scaled[i, 0])
  
X_train, y_train = np.array(X_train), np.array(y_train)

# Reshaping
X_train = np.reshape(X_train,(X_train.shape [0], X_train.shape [1], 1))


# Importing the Keras Libraries and packages 
from keras.models import Sequential 
from keras.layers import Dense 
from keras.layers import LSTM
from keras.layers import Dropout


# 啟用 RNN
regressor = Sequential ()


# 添加 LSTM layer 和要丟掉的資訊設置,會發現這邊就是一個 loop

regressor.add(LSTM(units = 50, return_sequences = True, input_shape = (X_train.shape [1], 1)))
regressor.add(Dropout (0.2))

regressor.add(LSTM(units = 50, return_sequences = True))
regressor.add(Dropout (0.2))

regressor.add(LSTM(units = 50, return_sequences = True))
regressor.add(Dropout (0.2))

regressor.add(LSTM(units = 50))
regressor.add(Dropout (0.2))

# output layer
regressor.add(Dense (units = 1))

regressor.compile(optimizer = 'adam', loss = 'mean_squared_error')


regressor.fit(X_train, y_train, epochs = 100, batch_size = 32)


# 進行測試
dataset_test = pd.read_csv('/content/Google_Stock_Price_Test.csv')
real_stock_price = dataset_test.iloc[:, 1:2].values


# 獲得 2017 年股價預測
dataset_total = pd.concat ((dataset_train['Open'], dataset_test['Open']), axis = 0)
inputs = dataset_total[len(dataset_total) - len(dataset_test) - 60:].values
inputs = inputs.reshape(-1,1)
inputs = sc.transform(inputs)
X_test = []
for i in range(60, 80):
  X_test.append(inputs[i-60:i, 0])


X_test = np.array(X_test)
X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))
predicted_stock_price = regressor.predict(X_test)
predicted_stock_price = sc.inverse_transform(predicted_stock_price)


# 結果視覺化
plt.plot (real_stock_price, color = 'red', label = 'Real Google Stock Price')
plt.plot(predicted_stock_price, color = 'blue', label = 'Predicted Google Stock Price') 
plt.title ('Google Stock Price Prediction')
plt.xlabel('Time')
plt.ylabel('Google Stock Price')
plt.legend ()
plt.show()

輸出結果為:

re

資料來源


上一篇
Day 25 NLP 中的 依存句法分析(Dependency Parsing)介紹與實作
下一篇
Day 27 雙向長短記憶網路(Bi-directional Long Short-Term Memory, BiLSTM)
系列文
語言學與NLP30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言